package drds.server.memory.unsafe.ringbuffer.common.waitStrategy.impl;

import java.util.concurrent.locks.LockSupport;

import drds.server.memory.unsafe.ringbuffer.common.barrier.SequenceBarrier;
import drds.server.memory.unsafe.ringbuffer.common.sequence.Sequence;
import drds.server.memory.unsafe.ringbuffer.common.waitStrategy.WaitStrategy;
import drds.server.memory.unsafe.ringbuffer.exception.AlertException;

/**
 * @author lmax.Disruptor
 * @version 3.3.5
 * @date 2016/8/1
 */
public class SleepingWaitStrategy implements WaitStrategy {
	// 重试200次
	private static final int DEFAULT_RETRIES = 200;
	private final int retries;

	public SleepingWaitStrategy() {
		this(DEFAULT_RETRIES);
	}

	public SleepingWaitStrategy(int retries) {
		this.retries = retries;
	}

	@Override
	public long waitFor(final long sequence, Sequence cursor, final Sequence dependentSequence, final SequenceBarrier barrier) throws AlertException, InterruptedException {
		long availableSequence;
		int counter = retries;
		// 直接检查dependentSequence.get() < sequence
		while ((availableSequence = dependentSequence.get()) < sequence) {
			counter = applyWaitMethod(barrier, counter);
		}

		return availableSequence;
	}

	@Override
	public void signalAllWhenBlocking() {
	}

	private int applyWaitMethod(final SequenceBarrier barrier, int counter) throws AlertException {
		// 检查是否需要终止
		barrier.checkAlert();
		// 如果在200~100,重试
		if (counter > 100) {
			--counter;
		}
		// 如果在100~0,调用Thread.yield()让出CPU
		else if (counter > 0) {
			--counter;
			Thread.yield();
		}
		// <0的话，利用LockSupport.parkNanos(1L)来sleep最小时间
		else {
			LockSupport.parkNanos(1L);
		}
		return counter;
	}
}
